package optimizacion;


public abstract class Cromosoma {

	public GenBinario[] genes;
    public int numGenes;    
    
    protected int longitud;
    
    public double aptitud;
    protected double aptitudRev;
    protected double aptitudEscaladoLineal;    
    protected double puntuacion;
    protected double puntuacionAcumulada; 
    
    protected double tolerancia; 
    
    public Cromosoma(int numGenes, double tolerancia){
    	this.numGenes = numGenes;
    	this.tolerancia = tolerancia;
    	this.genes = new GenBinario[numGenes];
    }
    
    public Cromosoma(){
    
    }
	
    /**
     * Crea los genes
     * @param min
     * @param max
     */
    public void crearGenes(double min, double max){
		for (int i=0; i<numGenes; i++)
			genes[i] = new GenBinario(min, max, tolerancia);   
	}
    
    /**
     * Crea un gen iesimo.
     * Se usa para cromosomas que tienen genes con distinto min y max
     * @param min
     * @param max
     */
    public void crearGenIesimo(double min, double max, int i){
    	genes[i] = new GenBinario(min, max, tolerancia);   
	}
   
    /**
     * Calcula la longitud de los genes. 
     * Tienen que estar creados con crearGene
     * @return
     */
    public double calcularLongitud(){
		longitud = 0;
		for (int i=0; i<numGenes; i++)  
			longitud += genes[i].longitud;
		return longitud;
	}
    
//    public ArrayList<Integer> genotipoToArrayList() {
//    	ArrayList<Integer> al = new ArrayList<Integer>();
//    	
//    	for (int i = 0; i < numGenes; i++)
//    		al.addAll(genes[i].genotipoToArrayList());
//    	
//		return al;
//	}
    
    /**
     * Inicializa los genes generando su genotipo con valores random
     */
	public void inicializar(int valorSemilla, boolean semilla){
		for (int i=0; i<numGenes; i++)  
			genes[i].inicializar(valorSemilla, semilla);
	}
	
	/**
	 * Calcula el fenotipo de un iesimo gen
	 * @param min
	 * @param max
	 * @param i
	 * @return
	 */
	public double calcularFenotipoIesimo(double min, double max, int i){
		return genes[i].calcularFenotipo(min, max);
	}
	
	/**
	 * Calcula la aptitud del cromosoma
	 * @return
	 */
	public abstract double calcularAptitud();
	
	public abstract double revisarAptitud(double rev);
	
	/**
	 * Calcula la aptitud con escalado lineal
	 * @param P
	 * @param media
	 * @param cmax
	 * @param cmin
	 * @return
	 */
	public double calcularAptitudEscaladoLineal(double P, double media, double cmax, double cmin) {   
		double a = ((P - 1) * media) / (cmax - media);
		
		if (a < 0) // // para evitar negativos y que de valores erroneos
			a = media / (media - cmin);
			
		a = a + 0.05; // para evitar 0 y que de valores erroneos
		
		double b = (1 - a) * media; 		
		
    	aptitudEscaladoLineal =  a * aptitudRev + b;
    	
    	//System.out.println("----- m: " + media + ", a:" + a + ", b: " + b+ ",a:" + aptitud +", aR: "  + aptitudRev + ", aEL: " + aptitudEscaladoLineal);
    	
    	return aptitudEscaladoLineal;
    } 
	
	public double calcularAptitudRevisadaMinimizacion(double cmax) {
		aptitudRev =  Math.abs(cmax*1.05) - aptitud; // he puesto abs porque si son todos negativos, uno se quedaria negativo
    	return aptitudRev;
	}

//	public double calcularAptitudRevisadaMaximizacion(double cmin) {
//		aptitudRev =  aptitud + Math.abs(cmin*1.05); 
//    	return aptitudRev;
//	}  
	
	/**
	 * Calcula la puntuacion de un cromosoma
	 * @param total
	 * @return
	 */
	public double calcularPuntuacion(double total){
		puntuacion = aptitudEscaladoLineal / total;
		return puntuacion;
	}
	
	/**
	 * Calcula la puntuacion acumulada de un cromosoma
	 * @param acumulado
	 * @return
	 */
	public double calcularPuntuacionAcumulada(double acumulado){
		puntuacionAcumulada = puntuacion + acumulado;
		return puntuacionAcumulada;
	}    
    
	
	public int damePosGenSegunPuntoCruce(int puntoCruce){
		
		int i = 0;
		int longAux = 0;
		
		while (i < numGenes && longAux < puntoCruce){
			longAux += genes[i].longitud;
			i++;
		}
		
		return i--;
	}
}
